# coding: utf-8

import sys

from ala_classes import TokenType as T, Token
from scanner import PythonScanner
from parser_ import Parser, SyntaxTreeOptimizer
from semantic_analyzer import SemanticAnalyzer
from codegen.codegen import CodeGenerator
from ala_classes.exceptions import *
import lib.color_console as cons


def wrap_header(text, length=79):
    res = u"=" * length + u"\n"
    res += text.center(length).rstrip() + u"\n"
    res += u"=" * length
    return res


def wrap_lines(text, length=79):
    text_copy = text
    res = u""
    while text_copy:
        line = text_copy[:length]
        if length < len(text_copy):
            line_length = line.rfind(u" ")
            if line_length != -1:
                line = text_copy[:line_length]
                text_copy = text_copy[line_length + 1:]
            else:
                text_copy = text_copy[length:]
        else:
            text_copy = text_copy[length:]
        res += line + u"\n"
    return res[:-1]  # Удаляем последний перенос строки


def handle_exception(e):
    print_(debug_mode=False)
    cons.set_text_attr(cons.FOREGROUND_RED | cons.DEFAULT_BG | cons.FOREGROUND_INTENSITY)
    print_(u"Ошибка: {0}".format(e.message), debug_mode=False)
    print_(u"Ошибка: {0}".format(e.message))
    cons.set_text_attr(cons.DEFAULT_COLORS | cons.DEFAULT_BG)
    print_(debug_mode=False)
    if isinstance(e, AlaError) and e.line_number:
        line_number = scanner.empty_lines_mapping[int(e.line_number)]
        print_(u"Строка {0}:".format(line_number), debug_mode=False)
        print_(u"{0}".format(src_code_lines[line_number - 1].replace(u" ", u"·").replace(u"\t", u"·")), debug_mode=False)
    cons.set_text_attr(cons.DEFAULT_COLORS | cons.DEFAULT_BG | cons.FOREGROUND_INTENSITY)
    exit(1)


def print_(args=None, debug_mode=True, color=cons.DEFAULT_COLORS):
    if SILENT:
        return
    cons.set_text_attr(color | cons.DEFAULT_BG | cons.FOREGROUND_INTENSITY)
    if not DEBUG ^ debug_mode:
        if args is not None:
            print args
        else:
            print
    cons.set_text_attr(cons.DEFAULT_COLORS | cons.DEFAULT_BG | cons.FOREGROUND_INTENSITY)


if __name__ == '__main__':
    try:
        DEBUG = u"--debug" in sys.argv
        SILENT = u"--silent" in sys.argv

        if len(sys.argv) == 1:
            raise Exception(u"Не задано имя файла")
        src_file_name = unicode(sys.argv[1])
        grammar_table_file_name = u'grammar/ala_table.xml'

        try:
            input_file = open(src_file_name, 'r')
        except Exception:
            raise Exception(u"Невозможно открыть файл '{0}'".format(src_file_name))

        print_(wrap_header(u"Сканирование файла исходного кода '{0}'".format(src_file_name)))
        print_(u"Сканирование файла исходного кода '{0}'...".format(src_file_name),
               debug_mode=False, color=cons.FOREGROUND_CYAN)
        src_code_lines = input_file.readlines()
        input_file.seek(0)
        scanner = PythonScanner(input_file)
        tokens = scanner.get_all_tokens()
        print_(wrap_lines(u"Токены: {0}".format(tokens)))
        print_()
        print_()

        print_(wrap_header(u"Парсинг токенов по грамматике из файла '{0}'".format(grammar_table_file_name)))
        print_(u"Парсинг токенов...", debug_mode=False, color=cons.FOREGROUND_CYAN)
        tokens.append(Token(T.PARSER_EOF))
        parser_ = Parser(tokens, grammar_table_file_name)
        tree = parser_.run()
        print_(u"Сырое синтаксическое дерево:")
        print_(tree.as_strings())
        print_()
        print_()

        print_(wrap_header(u"Оптимизация дерева"))
        print_(u"Оптимизация дерева...", debug_mode=False, color=cons.FOREGROUND_CYAN)
        syntax_tree_optimizer = SyntaxTreeOptimizer(tree)
        syntax_tree_optimizer.run()
        tree = syntax_tree_optimizer.tree
        print_(u"Результат:")
        print_(tree.as_strings())
        print_()
        print_()

        print_(wrap_header(u"Проверка типов"))
        print_(u"Семантический анализ...", debug_mode=False, color=cons.FOREGROUND_CYAN)
        semantic_analyzer = SemanticAnalyzer(tree)
        semantic_analyzer.run1()
        tree = semantic_analyzer.tree
        print_(u"Шаг 1. Результат:")
        print_()
        print_(tree.as_strings())
        semantic_analyzer.run2()
        tree = semantic_analyzer.tree
        print_(u"Шаг 2. Результат:")
        print_()
        print_(tree.as_strings())
        print_(u"Глобальная таблица символов:")
        print_(semantic_analyzer.global_symbol_table)
        print_()
        print_()

        print_(wrap_header(u"Генерация кода"))
        print_(u"Генерация кода...", debug_mode=False, color=cons.FOREGROUND_CYAN)
        try:
            codegen = CodeGenerator(src_file_name, tree, semantic_analyzer.global_symbol_table)
            print_(u"Компиляция...")
            codegen.compile()
            print_(u"Компиляция завершена!")
        except AlaCodeGeneratorException as error:
            print_(u"При компиляции возникли ошибки:")
            print_(error)
        except AlaNotImplementedException as error:
            print_(u"Попытка скомпилировать нереализовнаые части языка Python:")
            print_(error)
        print_()
        print_(u"Компиляция завершена успешно.", debug_mode=False, color=cons.FOREGROUND_GREEN)
        exit(0)
    except AlaError as e:
        handle_exception(e)
    except Exception as e:
        handle_exception(e)